/////////////////////////////////////////////////////////////////////////////////////////////
// Filename: StateMachine.h
// (c) Dave Ottley, 2012. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////////////////
#ifndef STATEMACHINE_H
#define STATEMACHINE_H

#include "State.h"
#include "Telegram.h"
//template <class T> class State;

template <class entity_type>
class StateMachine
{
private:
	entity_type*		mOwner;
	State<entity_type>*	mCurrentState;
	State<entity_type>* mPreviousState;
	State<entity_type>* mGlobalState;
public:
	StateMachine(entity_type* owner) : 
	mOwner(owner),
	mCurrentState(0),
	mPreviousState(0),
	mGlobalState(0)
	{ }
	void SetCurrentState(State<entity_type>* s) { mCurrentState = s; }
	void SetGlobalState(State<entity_type>* s) { mGlobalState = s; }
	void SetPreviousState(State<entity_type>* s) { mPreviousState = s; }

	void Update() const
	{
		if(mGlobalState) mGlobalState->Execute(mOwner);
		if(mCurrentState) mCurrentState->Execute(mOwner);
	}

	void ChangeState(State<entity_type>* pNewState)
	{
		assert(pNewState && "<StateMachine::ChangeState>: trying to change to a null state");

		mPreviousState = mCurrentState;
		mCurrentState->Exit(mOwner);
		mCurrentState = pNewState;
		mCurrentState->Enter(mOwner);
	}

	void RevertToPreviousState() { ChangeState(mPreviousState); }

	//accessors
	const State<entity_type>* GetCurrentState() const { return mCurrentState; }
	const State<entity_type>* GetGlobalState() const { return mGlobalState; }
	const State<entity_type>* GetPreviousState() const { return mPreviousState; }

	bool IsInState(const State<entity_type>& st) const { return mCurrentState == st; }
	bool HandleMessage(const Telegram& msg) const
	{
		// Route the message first through the currents state, then through the global
		// state if the current state cannot handle the message.
		if(mCurrentState && mCurrentState->OnMessage(mOwner, msg))
		{
			return true;
		}

		if(mGlobalState && mGlobalState->OnMessage(mOwner, msg))
		{
			return true;
		}

		return false;
	}

};

#endif  // STATEMACHINE_H